/* 
 * File:   Lesson16.cpp
 * Author: jose
 * 
 * Created on March 30, 2012, 4:23 PM
 */

#include "Lesson16.h"
#include "Timer.h"
#include "SdlUtils.h"
#include <sstream>
#include <string>

Lesson16::Lesson16() {
}

Lesson16::Lesson16(const Lesson16& orig) {
}

Lesson16::~Lesson16() {
}

//The dimensions of the dot
const int DOT_WIDTH = 20;
const int DOT_HEIGHT = 20;

//The surfaces
SDL_Surface *dot = NULL;

class Dot {
private:
    //The X and Y offsets of the dot
    int x, y;

    //The velocity of the dot
    int xVel, yVel;

    int screenWidth, screenHeight;

public:
    //Initializes the variables
    Dot(int screenWidth, int screenHeight);

    //Takes key presses and adjusts the dot's velocity
    void handle_input(SDL_Event event);

    //Moves the dot
    void move();

    //Shows the dot on the screen
    void show(SDL_Surface* screen);
};

//Keep track of the frame count 
int frame = 0;
//Timer used to calculate the frames per second 
Timer fpsDisplay;
//Timer used to update the caption 
Timer update;

bool Lesson16::init() {
    //Initialize all SDL subsystems
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1) {
        return false;
    }

    //Set up the screen
    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);

    //If there was an error in setting up the screen
    if (screen == NULL) {
        return false;
    }

    //Set the window caption
    SDL_WM_SetCaption("Move the Dot", NULL);

    //If everything initialized fine
    return true;
}

bool Lesson16::load_files() {
    //Load the dot image
    dot = SdlUtils::loadImage("dot.bmp");

    //If there was a problem in loading the dot
    if (dot == NULL) {
        return false;
    }

    //If everything loaded fine
    return true;
}

void Lesson16::clean_up() {
    //Free the surface
    SDL_FreeSurface(dot);

    //Quit SDL
    SDL_Quit();
}

Dot::Dot(int screenWidth, int screenHeight) {
    //Initialize the offsets
    x = 0;
    y = 0;

    //Initialize the velocity
    xVel = 0;
    yVel = 0;

    this->screenHeight = screenHeight;
    this->screenWidth = screenWidth;
}

void Dot::handle_input(SDL_Event event) {
    //If a key was pressed
    if (event.type == SDL_KEYDOWN) {
        //Adjust the velocity
        switch (event.key.keysym.sym) {
            case SDLK_UP: yVel -= DOT_HEIGHT / 2;
                break;
            case SDLK_DOWN: yVel += DOT_HEIGHT / 2;
                break;
            case SDLK_LEFT: xVel -= DOT_WIDTH / 2;
                break;
            case SDLK_RIGHT: xVel += DOT_WIDTH / 2;
                break;
        }
    }        //If a key was released
    else if (event.type == SDL_KEYUP) {
        //Adjust the velocity
        switch (event.key.keysym.sym) {
            case SDLK_UP: yVel += DOT_HEIGHT / 2;
                break;
            case SDLK_DOWN: yVel -= DOT_HEIGHT / 2;
                break;
            case SDLK_LEFT: xVel += DOT_WIDTH / 2;
                break;
            case SDLK_RIGHT: xVel -= DOT_WIDTH / 2;
                break;
        }
    }
}

void Dot::move() {
    //Move the dot left or right
    x += xVel;

    //If the dot went too far to the left or right
    if ((x < 0) || (x + DOT_WIDTH > this->screenWidth)) {
        //move back
        x -= xVel;
    }

    //Move the dot up or down
    y += yVel;

    //If the dot went too far up or down
    if ((y < 0) || (y + DOT_HEIGHT > this->screenHeight)) {
        //move back
        y -= yVel;
    }
}

void Dot::show(SDL_Surface* screen) {
    //Show the dot
    SdlUtils::applySurface(x, y, dot, screen);
   // SdlUtils::applySurface(15, 15, dot, screen);
}

int Lesson16::Run() {
    SDL_Event event;

    //Quit flag
    bool quit = false;

    //The dot that will be used
    Dot myDot(SCREEN_WIDTH, SCREEN_HEIGHT);

    //The frame rate regulator
    Timer fps;

    //Initialize
    if (init() == false) {
        return 1;
    }

    //Load the files
    if (load_files() == false) {
        return 1;
    }

    //Start the update timer 
    update.start();
    fpsDisplay.start();

    //While the user hasn't quit
    while (quit == false) {
        //Start the frame timer
        fps.start();

        //While there's events to handle
        while (SDL_PollEvent(&event)) {
            //Handle events for the dot
            myDot.handle_input(event);

            //If the user has Xed out the window
            if (event.type == SDL_QUIT) {
                //Quit the program
                quit = true;
            }
        }

        //Move the dot
        myDot.move();

        //Fill the screen white
        SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));

        //Show the dot on the screen
        myDot.show(screen);

        //Update the screen
        if (SDL_Flip(screen) == -1) {
            return 1;
        }

        //Cap the frame rate
        if (fps.get_ticks() < 1000 / FRAMES_PER_SECOND) {
            SDL_Delay((1000 / FRAMES_PER_SECOND) - fps.get_ticks());
        }

        frame++;

        if (update.get_ticks() > 1000) {
            //The frame rate as a string 
            std::stringstream caption;
            //Calculate the frames per second and create the string 
            caption << "Average Frames Per Second: " << frame / (fpsDisplay.get_ticks() / 1000.f);
            //Reset the caption 
            SDL_WM_SetCaption(caption.str().c_str(), NULL);
            //Restart the update timer
            update.start();
        }
    }

    //Clean up
    clean_up();

    return 0;
}